package com.atguigu.demo;

import org.junit.Test;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;

/**
 * @Author 孔德成
 * @Slogan 致敬大师，致敬未来的你
 * @date 2021/8/10
 */
public class BlockingQueueDemo {
    /**
     * 测试队列满时，使用 add 方法添加元素抛出异常
     */
    @Test
    public void testAddException() {
        BlockingQueue<String> queue = new ArrayBlockingQueue<>(3);
        // 添加元素
        System.out.println(queue.add("a"));
        System.out.println(queue.add("b"));
        System.out.println(queue.add("c"));
        // 获取队列的头元素，但不移除
        System.out.println(queue.element());
        // 队列已满，继续添加元素
        System.out.println(queue.add("x"));
    }

    /**
     * 测试队列为空时，使用 remove 方法移除元素抛出异常
     */
    @Test
    public void testRemoveException() {
        BlockingQueue<String> queue = new ArrayBlockingQueue<>(3);
        // 队列为空，移除元素
        queue.remove();
    }

    /**
     * 测试队列满时，使用 offer 添加元素失败，返回 false,不会抛出异常
     */
    @Test
    public void testOffer() {
        BlockingQueue<String> queue = new ArrayBlockingQueue<>(3);
        // 添加元素
        System.out.println(queue.offer("a"));
        System.out.println(queue.offer("b"));
        System.out.println(queue.offer("c"));
        // 获取队列的头元素，但不移除
        System.out.println(queue.peek());
        // 队列已满，继续添加元素
        System.out.println(queue.offer("x"));
    }

    /**
     * 测试队列为空时，使用 poll 方法移除元素返回 null, 不会抛出异常
     */
    @Test
    public void testPoll() {
        BlockingQueue<String> queue = new ArrayBlockingQueue<>(3);
        // 队列为空，移除元素
        System.out.println(queue.poll());
    }

    /**
     * 测试当阻塞队列满时，生产者线程继续往队列里 put 元素，队列会一直阻塞生产者线程直到队列可以继续 put 数据 or 响应中断退出
     */
    public static void testPut() {
        BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(3);
        new Thread(() -> {
            for (int i = 0; i < 4; i++) {
                try {
                    queue.put(i);
                    System.out.println(Thread.currentThread().getName() + "\t----put " + i);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "A").start();
        try {
            // 延时2秒，取走一个元素, 使得队列可用，唤醒线程A
            TimeUnit.SECONDS.sleep(2);
            Integer take = queue.take();
            System.out.println(Thread.currentThread().getName() + "\t----take " + take);

        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 当阻塞队列空时，消费者线程试图从队列里 take 元素，队列会一直阻塞消费者线程直到队列可用
     */
    public static void testTake() {
        BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(2);
        // 线程 B 取 2 个元素
        new Thread(() -> {
            for (int i = 0; i < 2; i++) {
                try {
                    Integer take = queue.take();
                    System.out.println(Thread.currentThread().getName() + "\t----take " + take);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "B").start();
        try {
            // 延时1秒，添加一个元素, 使得队列可用，唤醒线程B
            for (int i = 0; i < 2; i++) {
                TimeUnit.SECONDS.sleep(1);
                queue.put(i);
                System.out.println(Thread.currentThread().getName() + "\t----put " + i);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 测试生产者阻塞超时退出
     */
    @Test
    public void testOfferTimeOut() {
        BlockingQueue<String> queue = new ArrayBlockingQueue<>(3);
        // 添加元素
        System.out.println(queue.offer("a"));
        System.out.println(queue.offer("b"));
        System.out.println(queue.offer("c"));

        try {
            // 队列已满，继续添加元素，该线程会阻塞
            queue.offer("x", 3L, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
//        testPut();
        testTake();

    }
}
